<?php
/**
 * YLockBackendAbstract.php
 *
 * @author Hua Yang <htmlcook@gmail.com>
 * @since 2.0
 */

Yii::import('common.components.lock.YLockBackendInterface');

/**
 * Class YLockBackendAbstract
 */
abstract class YLockBackendAbstract extends CApplicationComponent implements YLockBackendInterface
{
	/**
	 * @var string
	 */
	protected $lockId;

	/**
	 * Existing locks for this page.
	 *
	 * @var array
	 */
	protected $locks = array();

	/**
	 * @param string $name
	 * @param int $delay
	 * @return bool
	 */
	public function wait($name, $delay = 30)
	{
		$delay = (int)$delay * 1000000;

		// Begin sleeping at 25ms.
		$sleep = 25000;
		while ($delay > 0) {
			// This function should only be called by a request that failed to get a
			// lock, so we sleep first to give the parallel request a chance to finish
			// and release the lock.
			usleep($sleep);
			// After each sleep, increase the value of $sleep until it reaches
			// 500ms, to reduce the potential for a lock stampede.
			$delay = $delay - $sleep;
			$sleep = min(500000, $sleep + 25000, $delay);
			if ($this->lockMayBeAvailable($name)) {
				// No longer need to wait.
				return false;
			}
		}
		// The caller must still wait longer to get the lock.
		return true;
	}

	/**
	 * @return string
	 */
	public function getLockId()
	{
		if (!isset($this->lockId)) {
			$this->lockId = uniqid(mt_rand(), true);
		}
		return $this->lockId;
	}
}